#ifndef __CODE_COMMENT_INFO_H_
#define __CODE_COMMENT_INFO_H_

#include "llvm/Support/Mutex.h"
#include "llvm/Support/JSON.h"

#include <string>
#include <vector>
#include <map>
#include <set>

typedef enum {
    NULL_COMMENT = 0,
    #undef  CODE_COMMENT_TYPE_KV
    #define CODE_COMMENT_TYPE_KV(x, y) x,
    #include "code_comment_type.def"
} CommentType;

class CodeCommentInfoNode {
public:
    CodeCommentInfoNode() 
    {
        mParent = nullptr;
        mKeyInfo.clear();
        mChildren.clear();
        mCommentType = NULL_COMMENT;
    }

    ~CodeCommentInfoNode() {
        if (nullptr != mParent) {
            delete mParent;
        }
        for(size_t i = 0; i < mChildren.size(); i++) {
            if(nullptr != mChildren[i]) {
                delete mChildren[i];
            }
        }
        mChildren.clear();
    }

    void toJson(llvm::json::Object& obj);
    std::string formatType();

    CodeCommentInfoNode*                mParent;
    CommentType                         mCommentType;
    std::map<std::string, std::string>  mKeyInfo;
    std::vector<CodeCommentInfoNode*>   mChildren;
};

class CodeCommentInfo {
public:
    explicit CodeCommentInfo()
        {
            mCurrentNodePtr = &mRootNode;
        }
    
    ~CodeCommentInfo() 
    {
    }

    void addInfo(CodeCommentInfoNode* cmtNodePtr);
    void pushInfo(CodeCommentInfoNode* cmtNodePtr);
    void pop();
    bool toJson(llvm::json::Object& obj);

private:
    CodeCommentInfoNode mRootNode;
    CodeCommentInfoNode* mCurrentNodePtr;
};

class CodeCommentInfoManager {
public:
    explicit CodeCommentInfoManager(std::string outFile)
        : mOutFile(outFile)
        {}
    
    CodeCommentInfo* getOrAddCodeCommentInfo(std::string ident, std::string funcKey);
    bool doWriteOut();
private:
    bool registerFuncInfo(std::string ident, std::string funcName);
    std::string getRealFileIdent(const std::string& ident);
private:
    std::string mOutFile;
    std::map<std::string, CodeCommentInfo*>  mCodeCommentInfoMap;
    std::map<std::string, std::set<std::string>> mCodeCommentInfoForFunc;
    llvm::sys::Mutex mRegisterMutex;
};

#endif  // __CODE_COMMENT_INFO_H_